use iron::prelude::*;

use iron::status::Status;
use iron::{typemap, AfterMiddleware, BeforeMiddleware};
use log::*;
use logger::Logger;
use mount::Mount;
use router::{NoRoute, Router};
use staticfile::Static;
use std::path::Path;
use std::time::Duration;
use time::precise_time_ns;
use ttl_cache::TtlCache;

struct ResponseTime;

impl typemap::Key for ResponseTime {
    type Value = u64;
}

struct Custom404;

impl AfterMiddleware for Custom404 {
    fn catch(&self, _: &mut Request, err: IronError) -> IronResult<Response> {
        if err.error.is::<NoRoute>() {
            Ok(Response::with((Status::NotFound, "Custom 404 response")))
        } else {
            Err(err)
        }
    }
}

fn hello_world(_: &mut Request, query: &str) -> IronResult<Response> {
    let duration = Duration::from_secs(60 * 60);
    let mut cache = TtlCache::new(2);
    cache.insert(1, "echo: ".to_owned() + query, duration);
    let ret = cache.get_mut(&1).unwrap();
    let new_string = format!("{{\"ret\":\"{}\"}}", ret);

    Ok(Response::with((iron::status::Ok, new_string.to_owned())))
}

fn handler(req: &mut Request) -> IronResult<Response> {
    let query = req
        .extensions
        .get::<Router>()
        .unwrap()
        .find("query")
        .unwrap_or("/")
        .to_owned();
    hello_world(req, &query)
}

fn main() {
    let mut router = Router::new();
    router.get("/:query", handler, "query");

    let mut mount = Mount::new();
    mount
        .mount("/", router)
        .mount("/docs/", Static::new(Path::new("target/doc")));
    let mut chain = Chain::new(mount);
    env_logger::init();
    let (logger_before, logger_after) = Logger::new(None);
    chain.link_before(logger_before);
    chain.link_after(logger_after);
    chain.link_after(Custom404);

    info!("running 3000 port,Ctrl+c stop it");
    Iron::new(chain).http("localhost:3000").unwrap();
}
